package util;

import conf.AppConfig;
import okhttp3.*;
import okhttp3.logging.HttpLoggingInterceptor;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class HttpUtil {
    private Logger logger = LoggerFactory.getLogger(HttpUtil.class);

    private OkHttpClient httpClient;

    public HttpUtil(HttpParams httpParams) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(@NotNull String message) {
                if (logger.isInfoEnabled()){
                    logger.info(message);
                }else if (logger.isDebugEnabled()) {
                    logger.debug(message);
                }
            }
        });
        if(logger.isDebugEnabled()){
            httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        }else if(logger.isInfoEnabled()){
            httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
        }else{
            httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
        }

        builder.addInterceptor(httpLoggingInterceptor);

        if(httpParams.isUseProxy()){
            builder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(httpParams.getProxyHttpHost(), httpParams.getProxyHttpPort())));
        }

        builder.connectTimeout(httpParams.getConnectTimeout(), TimeUnit.SECONDS);
        builder.readTimeout(httpParams.getReadTimeout(), TimeUnit.SECONDS);
        builder.writeTimeout(httpParams.getWriteTimeout(), TimeUnit.SECONDS);

        httpClient = builder.build();
    }

    private HttpUtilResponse request(Request request){
        try {
            Response response = httpClient.newCall(request).execute();
            HttpUtilResponse res = new HttpUtilResponse();
            res.setResponseBytes(response.body().bytes());
            res.setHeaders(response.headers());
            return res;
        } catch (IOException e) {
            logger.error("Get access to the link {} failed.", request.url());
            logger.error(e.getMessage(),e);
            throw new RuntimeException(e);
        }
    }
    public HttpUtilResponse get(String requestUrl){
        Request request = new Request.Builder().url(requestUrl).get().build();
        return request(request);
    }

    public HttpUtilResponse post(String requestUrl, byte[] requestData, String contentType){
        RequestBody requestBody = RequestBody.create(requestData, MediaType.parse(contentType));
        Request request = new Request.Builder().url(requestUrl).post(requestBody).build();
        return request(request);
    }

    public static class HttpUtilResponse{
        private byte[] responseBytes;
        private Map<String,String> headers;

        public void setResponseBytes(byte[] responseBytes) {
            this.responseBytes = responseBytes;
        }

        public String getResponseStr() {
            return new String(responseBytes, AppConfig.SYS_CHARSET);
        }

        public String getResponseStr(Charset charset) {
            return new String(responseBytes, charset);
        }

        public void setHeaders(Headers headers) {
            this.headers = new HashMap<>();
            Set<String> names = headers.names();
            names.forEach(name ->{
                this.headers.put(name, headers.get(name));
            });
        }

        public Map<String, String> getHeaders() {
            return headers;
        }

        @Override
        public String toString() {
            return "HttpUtilResponse{" +
                    "responseBytes=" + this.getResponseStr() +
                    ", headers=" + headers +
                    '}';
        }
    }

    public static class HttpParams{
        private String proxyHttpHost;
        private int proxyHttpPort;
        private boolean useProxy = false;

        private long connectTimeout = 10;
        private long readTimeout = 10;
        private long writeTimeout = 10;

        public String getProxyHttpHost() {
            return proxyHttpHost;
        }

        public void setProxyHttpHost(String proxyHttpHost) {
            this.proxyHttpHost = proxyHttpHost;
        }

        public int getProxyHttpPort() {
            return proxyHttpPort;
        }

        public void setProxyHttpPort(int proxyHttpPort) {
            this.proxyHttpPort = proxyHttpPort;
        }

        public boolean isUseProxy() {
            return useProxy;
        }

        public void setUseProxy(boolean useProxy) {
            this.useProxy = useProxy;
        }

        public long getConnectTimeout() {
            return connectTimeout;
        }

        public void setConnectTimeout(long connectTimeout) {
            this.connectTimeout = connectTimeout;
        }

        public long getReadTimeout() {
            return readTimeout;
        }

        public void setReadTimeout(long readTimeout) {
            this.readTimeout = readTimeout;
        }

        public long getWriteTimeout() {
            return writeTimeout;
        }

        public void setWriteTimeout(long writeTimeout) {
            this.writeTimeout = writeTimeout;
        }

        @Override
        public String toString() {
            return "HttpParams{" +
                    "proxyHttpHost='" + proxyHttpHost + '\'' +
                    ", proxyHttpPort=" + proxyHttpPort +
                    ", useProxy=" + useProxy +
                    ", connectTimeout=" + connectTimeout +
                    ", readTimeout=" + readTimeout +
                    ", writeTimeout=" + writeTimeout +
                    '}';
        }
    }

    @Override
    public String toString() {
        return "HttpUtil{" +
                "httpClient=" + httpClient +
                '}';
    }
}
